﻿#ifndef __INC_QG_ES2_DEV_H__
#define __INC_QG_ES2_DEV_H__

#ifdef _MSC_VER
#pragma once
#endif

#include "qg/qgasv.h"

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

//////////////////////////////////////////////////////////////////////////
// GLES2 디바이스

#define QG_ES2_MAX_TEXTURE				4

//
class ES2Device : public qgDevice
{
	KCH_SUBCLASS(ES2Device, qgDevice);
	KT_DECL_TYPE_INIT(ES2Device);
	KT_DECL_TYPE_FINAL(ES2Device);
	KCH_FRIEND(ES2Program);
	KCH_FRIEND(ES2ProgramWorker);

public:
	enum ExtensionIndex
	{
		EI_OES_PACKED_DEPTH_STENCIL,
		EI_OES_TEXTURE_FLOAT,
		EI_OES_TEXTURE_HALF_FLOAT,
		EI_EXT_TEXTURE_STORAGE,
		EI_EXT_COLOR_BUFFER_HALF_FLOAT,
		EI_EXT_TEXTURE_COMPRESSION_DXT1,
		EI_EXT_TEXTURE_COMPRESSION_S3TC,
		EI_ANGLE_TEXTURE_COMPRESSION_DXT3,
		EI_ANGLE_TEXTURE_COMPRESSION_DXT5,
		EI_OES_TEXTURE_NPOT,
		EI_OES_MAPBUFFER,
		EI_OES_RGB8_RGBA8,
		EI_MAX_VALUE
	};

	struct Prsn : public qgDevPrsn
	{
		kint					m_tex_active;
		qgRaszData				m_rasz_data;
		qgBlndData				m_blnd_data;
		bool					m_blnd_blend;
		bool					m_blnd_alpha;

		GLuint					m_shd_program;

		kint					ws_bind[8];
	};

	struct Debz : public qgDevDebz
	{
		qgTexture*				texw;
		qgBuffer*				vb;
		qgLayout*				lo;
		qgShader*				sdraw;
	};

private:
	EGLDisplay			_display;
	EGLSurface			_surface;
	EGLContext			_context;

	Prsn				_vprn;
	Debz				_vdeb;

private:
	ES2Device();
	~ES2Device();

public:
	K_OVR bool Layout(const qgSevLayout& e);

	K_OVR bool Enter(kint clearance);
	K_OVR bool Leave();
	K_OVR bool Flush();

	K_OVR void Draw(kint vertexcount, kint vertexstart);
	K_OVR void DrawIndexed(kint indexcount, kint vertexstart);

	K_OVR void DrawRect(const tpl::Rect&bound, const tpl::ColorValue& color, qgTexture* tex, const tpl::Quad* coord);
	K_OVR void DrawGlyph(const tpl::Rect&bound, const tpl::ColorValue& color, qgTexture* tex);
	K_OVR void DrawPolyLine(kint count, const tpl::Point pts[], const tpl::ColorValue colors[]);
	K_OVR void DrawPolyStrip(kint count, const tpl::Point* pts, const tpl::ColorValue* colors, qgTexture* tex, const tpl::Vec2* coords);

	K_OVR qgImage* ScreenCapture();

	K_OVR bool _SetRenderTarget(qgTexture* tex);

protected:
	K_OVR bool _Initialize(qgStub* stub, kint flags);
	K_OVR bool _ResetPrepare(const tpl::Point& size, bool prepare);
	K_OVR void _Finalize();

	K_OVR qgBuffer* _RoamImplBuffer(const qgArprBuffer& arpr);
	K_OVR qgLayout* _RoamImplLayout(qgLayoutData* data);
	K_OVR qgTexture* _RoamImplTexture(const qgArprTexture& arpr);
	K_OVR qgTexture* _RoamImplTexture(const qgArprImage& arpr);
	K_OVR qgTexture* _RoamImplMotionTexture(const char* filename, kint flags);
	K_OVR qgDepthBuffer* _RoamImplDepthBuffer(const tpl::Point& size);
	K_OVR qgShader* _RoamImplShader(const char* name);
	K_OVR qgRasz* _RoamImplRasz(const qgRaszData& data);
	K_OVR qgBlnd* _RoamImplBlnd(const qgBlndData& data);
	K_OVR qgSplr* _RoamImplSplr(const qgSplrData& data);

public:
	bool _InitializeExtension() throw();
	GLenum _GetError(const char** str = NULL, bool output = false) throw();

	void _InternalClear(kint clearance, const tpl::Color& color, kint stencil, float depth) throw();
	void _InternalDraw(kint texcount, kint vertexcount, kint vertexstart);
	void _InternalDrawIndexed(kint texcount, kint indexcount, kint vertexstart);

	bool _ActiveTexture(kint stage) throw();
	bool _CommitTexture(kint stage, qgTexture* tex) throw();
	void _CommitSampler(kint stage, const qgSplrData& nsp, qgSplrData& psp) throw();
	void _CommitRasterize(const qgRaszData& nrz, qgRaszData& prz) throw();
	void _CommitBlendState(const qgBlndData& nbd, qgBlndData& pbd) throw();
	bool _CommitLayout(kint stride, kint count, kpointer elmsptr) throw();
	bool _CommitShader() throw();

	bool _BindMtrl(ksize_t maxtexcount = QG_ES2_MAX_TEXTURE) throw();
	bool _BindShader() throw();
	bool _BindDraw() throw();
	bool _UnbindDraw() throw();
};

namespace _es2
{
	extern PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
	extern PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
	extern PFNEGLPOSTSUBBUFFERNVPROC eglPostSubBufferNV;
	extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
	extern PFNGLDELETEFENCESNVPROC glDeleteFencesNV;
	extern PFNGLGENFENCESNVPROC glGenFencesNV;
	extern PFNGLGETFENCEIVNVPROC glGetFenceivNV;
	extern PFNGLISFENCENVPROC glIsFenceNV;
	extern PFNGLFINISHFENCENVPROC glFinishFenceNV;
	extern PFNGLSETFENCENVPROC glSetFenceNV;
	extern PFNGLTESTFENCENVPROC glTestFenceNV;
	extern PFNGLMAPBUFFEROESPROC glMapBufferOES;
	extern PFNGLUNMAPBUFFEROESPROC glUnmapBufferOES;
	extern PFNGLGETBUFFERPOINTERVOESPROC glGetBufferPointervOES;

	extern bool TestCapsExt(kint nth);
}

#endif	// __INC_QG_ES2_DEV_H__
